/*
 * Author : Yuval Kovler 2011
 * 
 */
package implementation.client;

import java.io.IOException;
import java.util.Collection;
import org.apache.log4j.Logger;

import implementation.client.IUserInput.EUserAction;
import implementation.logger.CLoggerFactory;
import implementation.shared.Config;
import implementation.shared.INotification;
import implementation.shared.stubs.IForumStub;
import implementation.shared.stubs.IPostStub;
import implementation.shared.stubs.IThreadStub;
import implementation.shared.stubs.IUserStub;

public class Client {

    private static final String NOT_CONNECTED = "not connected";
    private static final String MSG_TO_THE_USER_ERROR_INVALID_ACTION = "Error - Invalid action";
    private static final String MSG_TO_THE_USER_ADDED_FRIEND = "successfully added friend";
    private static final String MSG_TO_THE_USER_ADDED_POST = "successfully added the post";
    private static final String MSG_TO_THE_USER_ADDED_THREAD = "successfully added the thread";
    private static final String MSG_TO_THE_USER_EDITED_POST = "successfully edited the post";
    private static final String MSG_TO_THE_USER_LOGGED_IN = "Logged out successfully";
    private static final String MSG_TO_THE_USER_REMOVED_FRIEND = "successfully removed friend";
    private static final String MSG_TO_THE_USER_REMOVED_POST = "successfully removed the post";
    private static final String MSG_TO_THE_USER_REMOVED_THREAD = "successfully removed the thread";
    private static final String MSG_TO_THE_USER_REGISTERD = "registered";
    private static final String MSG_TO_THE_USER_REGISTERD_LOGGED_IN = "logged in";
    //Default messages to the user:
    /*
    private static final String  MSG_TO_THE_USER_NOT_ADDED_FRIEND="sorry, could'nt add friend successfully -try again";
    private static final String  MSG_TO_THE_USER_NOT_ADDED_POST="sorry, could'nt add the post successfully -try again";
    private static final String  MSG_TO_THE_USER_NOT_ADDED_THREAD="sorry, could'nt add the thread successfully -try again";
    private static final String  MSG_TO_THE_USER_NOT_EDITED_POST="sorry, could'nt edit the post successfully -try again";
    private static final String  MSG_TO_THE_USER_NOT_LOGGED_IN="Login was unsuccessful, try again!!!";
    private static final String  MSG_TO_THE_USER_NOT_LOGGED_OUT="sorry, didn't logged out successfully - something went wrong";
    private static final String  MSG_TO_THE_USER_NOT_REGISTERD="sorry, could'nt register successfully -try again";
    private static final String  MSG_TO_THE_USER_NOT_REMOVED_FRIEND="sorry, could'nt remove friend successfully -try again";
    private static final String  MSG_TO_THE_USER_NOT_REMOVED_POST="sorry, could'nt remove the post successfully -try again";
    private static final String  MSG_TO_THE_USER_NOT_REMOVED_THREAD="sorry, could'nt remove the thread successfully -try again";
    private static final String  MSG_TO_THE_USER_PARSE_INT_ERROR="only integers allowed";
     */
    private static Collection<IForumStub> _forums;
    private static Collection<IThreadStub> _threads;
    private static Collection<IPostStub> _posts;
    
    private static int _threadId;
    private static int _forumId;
    private static int _postId;
    private static IPostStub _post;
    private static IEncryptor _encryptor;
    private static IServerStub _serverStub;
    private static IUI _ui;
    private static EUserAction _nextScreen;
    private static IUserInput userInput;
    private static final String HOST = "localhost";
    private static Logger Log;

    public static void main(String[] args) {

    	// logger
        try {
            Log = CLoggerFactory.getFileLogger("ClientSystemLogger", "C:/MaldaForumLogs/ClientSystem-Log.txt");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


        //create singletons for inside usage
        _encryptor = CClientFactory.getEncrptorSingelton();
        _serverStub = CClientFactory.getClientSideServerSingelton();
        //_ui=CClientSystemFactory.getUISingelton();
        _ui = CClientFactory.getUISingelton();

        
        if (!_serverStub.connect(HOST, Config.PORT)) {

            System.out.println(NOT_CONNECTED);
            _serverStub.close();
            System.exit(1);
        }


        //jump to main screen view
        _nextScreen = EUserAction.EShowMainScreen;

        // start notification listening thread:

        SwitchRunnable s = new SwitchRunnable(new Runnable() {

            public void run() {
                INotification n = _serverStub.getNotification();
                if (n!= null) {
                	_ui.showNotification(n);
                }
            }
        });

        Thread t = new Thread(s);
        t.start();
        execute();
        s.stop();
        t.interrupt();
        try {
            t.join();
        } catch (InterruptedException e) {
        }



        System.out.println("naiman maldavan - clientSystem ended");

    }

    public static void execute() {

        boolean run = true;
        while (run) {

            switch (_nextScreen) {

                case EShowMainScreen:
                    Log.debug("Trying to Show Main Screen");
                    ShowMainScreen();
                    break;

                case EProfile:
                    Log.debug("Trying to Show Profile Screen");
                    showProfile();
                    break;

                case EExit:
                    Log.debug("Trying to exit");
                    _serverStub.logout();
                    _serverStub.close();
                    run = false;
                    break;

                case ELogout:
                    Log.debug("Trying to logout");
                    logout();
                    _nextScreen = EUserAction.EShowMainScreen;
                    break;

                case ELogin:
                    Log.debug("Trying to Show login Screen");
                    login();
                    break;

                case ERegister:
                    Log.debug("Trying to Show register Screen");
                    register();
                    break;

                case EGetAllForums:
                    Log.debug("Trying to Show Forums Screen");
                    showForums();
                    break;

                case EGetForum:
                    Log.debug("Trying to Show Forum Screen");

                    showForum();
                    break;

                case EGetPost:
                    Log.debug("Trying to Show Post Screen");
                    showPost();

                    break;

                case EAddPost:
                    Log.debug("Trying to Show Add Post Screen");
                    addPost();
                    break;

                case EEditPost:
                    Log.debug("Trying to Show Edit Post Screen");
                    editPost();
                    break;

                case ERemovePost:
                    Log.debug("Trying to Show Remove Post Screen");
                    removePost();
                    break;

                case EGetThread:
                    Log.debug("Trying to Show Get Thread Screen");

                    showThread();
                    break;

                case EAddThread:
                    Log.debug("Trying to Show Add Thread Screen");
                    addThread();
                    break;


                case ERemoveThread:
                    Log.debug("Trying to Show Remove Thread Screen");
                    removeThread();
                    break;


                case EAddFriend:
                    Log.debug("Trying to Show Add Friend Screen");
                    addFriend();
                    break;


                case ERemoveFriend:
                    Log.debug("Trying to Show Remove Friend Screen");
                    removeFriend();
                    break;

                /*		
                case EGetFriends:
                getFriends();
                
                break;			     
                 */

                default:
                    Log.debug("Unkown Screen : " + _nextScreen.toString());
                    _ui.showClientSideError(MSG_TO_THE_USER_ERROR_INVALID_ACTION);
                    ShowMainScreen();
                    break;
            }
        }
    }

    private static void ShowMainScreen() {

        userInput = CClientFactory.getMainScreen();
        try {
            _ui.showMainScreen(userInput);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        _nextScreen = userInput.getSelectedAction();

    }

    private static void login() {

        String userName, encryptedPassword;
        userInput = CClientFactory.getloginScreen();

        try {
            _ui.showLogin(userInput);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        _nextScreen = userInput.getSelectedAction();

        //if the login action has been selected
        if (userInput.getSelectedAction().equals(EUserAction.ELogin)) {

            userName = (String) userInput.getParam(EUserParam.EUsername);
            encryptedPassword = _encryptor.encrypt((String) userInput.getParam(EUserParam.EPassword));

            //if the user has logged in successfully 
            if (_serverStub.login(userName, encryptedPassword)) {
                _nextScreen = EUserAction.EGetAllForums;
                _ui.showClientSideMessage(MSG_TO_THE_USER_REGISTERD_LOGGED_IN);
            } else {
                _ui.showClientSideError("Server:" + _serverStub.getErrorMessage());
                _nextScreen = EUserAction.ELogin;
            }

        } //if the back action has been selected -go  back to main screen
        else if (userInput.getSelectedAction().equals(EUserAction.EBack)) {
            _nextScreen = EUserAction.EShowMainScreen;
        }
    }

    private static void logout() {

        if (_serverStub.logout()) {
            _ui.showClientSideMessage(MSG_TO_THE_USER_LOGGED_IN);
            _nextScreen = EUserAction.EShowMainScreen;
        } else {
            _ui.showClientSideError("Server:" + _serverStub.getErrorMessage());
            _nextScreen = EUserAction.EGetAllForums;
        }

    }

    private static void register() {
        String userName, encryptedPassword;
        userInput = CClientFactory.getRegisterScreen();

        try {
            _ui.showRegister(userInput);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        _nextScreen = userInput.getSelectedAction();

        if (userInput.getSelectedAction().equals(EUserAction.ERegister)) { //if the register action has been selected

            userName = (String) userInput.getParam(EUserParam.EUsername);
            encryptedPassword = _encryptor.encrypt((String) userInput.getParam(EUserParam.EPassword));
            if (_serverStub.register(userName, encryptedPassword)) {//if the user has registered successfully 
                _nextScreen = EUserAction.EGetAllForums;
                _ui.showClientSideMessage(MSG_TO_THE_USER_REGISTERD);

            } else {
                _ui.showClientSideError("Server:" + _serverStub.getErrorMessage());
                _nextScreen = EUserAction.ERegister;
            }

        } //if the back action has been selected -go  back to main screen
        else if (userInput.getSelectedAction().equals(EUserAction.EBack)) {
            _nextScreen = EUserAction.EShowMainScreen;
        }

    }

    private static void showForums() {
        _forums = _serverStub.getForums();

        userInput = CClientFactory.getForumsScreen();

        _ui.showForumList(userInput, _forums);

        _nextScreen = userInput.getSelectedAction();
        if (_nextScreen == EUserAction.EGetForum) {
            _forumId = (Integer) userInput.getParam(EUserParam.EID);
        }
    }

    private static void showForum() {

        //_forum=_clientSideServer.getForum(_forumId);
        _threads = _serverStub.getThreads(_forumId);
        userInput = CClientFactory.getForumScreen();

        try {
            _ui.showForum(userInput, _threads);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        _nextScreen = userInput.getSelectedAction();

        //if the back action has been selected -go  back to forums screen
        if (_nextScreen.equals(EUserAction.EBack)) {
            _nextScreen = EUserAction.EGetAllForums;
        } else if (_nextScreen.equals(EUserAction.EGetThread)) {
            _threadId = (Integer) userInput.getParam(EUserParam.EID);
        }
    }

    private static void showThread() {

        //_thread=_clientSideServer.getThread(_threadId);
        _posts = _serverStub.getPosts(_threadId);

        userInput = CClientFactory.getThreadScreen();
        _ui.showThread(userInput, _posts);


        _nextScreen = userInput.getSelectedAction();

        //if the back action has been selected -go  back to the forum who contains this thread screen
        if (userInput.getSelectedAction().equals(EUserAction.EBack)) {
            _nextScreen = EUserAction.EGetForum;
        } else if (userInput.getSelectedAction().equals(EUserAction.EGetPost)) {
            _postId = (Integer) userInput.getParam(EUserParam.EID);
        }
    }

    private static void addThread() {

        String content, topic;
        userInput = CClientFactory.getAddThreadScreen();

        try {
            _ui.showAddThread(userInput);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        _nextScreen = userInput.getSelectedAction();


        if ((userInput.getSelectedAction().equals(EUserAction.EAddThread))) {
            topic = (String) userInput.getParam(EUserParam.ETopic);
            content = (String) userInput.getParam(EUserParam.EContent);
            if (_serverStub.addThread(_forumId, topic, content)) {
                _ui.showClientSideMessage(MSG_TO_THE_USER_ADDED_THREAD);
                _nextScreen = EUserAction.EGetForum;
            } else {
                _ui.showClientSideError("Server:" + _serverStub.getErrorMessage());
                _nextScreen = EUserAction.EAddThread;
            }
        } //if the back action has been selected -go  back to the forum who contains this post
        else if (userInput.getSelectedAction().equals(EUserAction.EBack)) {
            _nextScreen = EUserAction.EGetThread;
        }

    }

    private static void removeThread() {

        if (_serverStub.removeThread(_threadId)) {
            _ui.showClientSideMessage(MSG_TO_THE_USER_REMOVED_THREAD);
            _nextScreen = EUserAction.EGetForum;
        } else {
            _ui.showClientSideError("Server:" + _serverStub.getErrorMessage());
            _nextScreen = EUserAction.EGetThread;
        }
    }

    private static void showPost() {


        _post = _serverStub.getPost(_postId);

        Log.debug("Recived post id :" + _postId);

        userInput = CClientFactory.getPostScreen();
        _ui.showPost(userInput, _post);

        _nextScreen = userInput.getSelectedAction();

        //if the edit post action has been selected
        if (userInput.getSelectedAction().equals(EUserAction.EEditPost)) {
            _nextScreen = EUserAction.EEditPost;
        } //if the remove post action has been selected
        else if (userInput.getSelectedAction().equals(EUserAction.ERemovePost)) {
            _nextScreen = EUserAction.ERemovePost;
        } //if the back action has been selected -go  back to the forum who contains this thread screen
        else if (userInput.getSelectedAction().equals(EUserAction.EBack)) {
            _nextScreen = EUserAction.EGetThread;
        }

    }

    private static void addPost() {


        String content, topic;
        userInput = CClientFactory.getAddPostScreen();


        try {
            _ui.showAddPost(userInput);

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        _nextScreen = userInput.getSelectedAction();

        if ((userInput.getSelectedAction().equals(EUserAction.EAddPost))) {
            topic = (String) userInput.getParam(EUserParam.ETopic);
            content = (String) userInput.getParam(EUserParam.EContent);
            if (_serverStub.addPost(_threadId, topic, content)) {
                _ui.showClientSideMessage(MSG_TO_THE_USER_ADDED_POST);
                _nextScreen = EUserAction.EGetThread;//showThread(_thread.get_threadID());
            } else {
                _ui.showClientSideError("Server:" + _serverStub.getErrorMessage());
                _nextScreen = EUserAction.EAddPost;
            }
        } //if the back action has been selected -go  back to the thread who contains this post
        else if (userInput.getSelectedAction().equals(EUserAction.EBack)) {
            _nextScreen = EUserAction.EGetThread;
        }
    }

    private static void removePost() {


        if (_serverStub.removePost(_post.getPostId())) {
            _ui.showClientSideMessage(MSG_TO_THE_USER_REMOVED_POST);
            _nextScreen = EUserAction.EGetThread;
        } else {
            _ui.showClientSideError("Server:" + _serverStub.getErrorMessage());
            _nextScreen = EUserAction.EGetPost;
        }
    }

    private static void editPost() {

        String content, topic;
        userInput = CClientFactory.getEditPostScreen();


        try {
            _ui.showAddPost(userInput);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        _nextScreen = userInput.getSelectedAction();

        if ((userInput.getSelectedAction().equals(EUserAction.EEditPost))) {
            topic = (String) userInput.getParam(EUserParam.ETopic);
            content = (String) userInput.getParam(EUserParam.EContent);
            if (_serverStub.editPost(_post.getPostId(), topic, content)) {
                _ui.showClientSideMessage(MSG_TO_THE_USER_EDITED_POST);
                _nextScreen = EUserAction.EGetThread;//showThread(_thread.get_threadID());
            } else {
                _ui.showClientSideError("Server:" + _serverStub.getErrorMessage());
                _nextScreen = EUserAction.EEditPost;
            }
        } //if the back action has been selected -go  back to the thread who contains this post
        else if (userInput.getSelectedAction().equals(EUserAction.EBack)) {
            _nextScreen = EUserAction.EGetThread;
        }


    }


    /*
    private static void getFriends() {		
    userInput=_getFriendsUserOutputInput;
    
    try {
    _ui.showFriends(userInput, _clientSideServer.getFriends());
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    
    _nextScreen=userInput.getSelectedAction();
    
    }
    
     */
    private static void removeFriend() {

        userInput = CClientFactory.getRemoverFriendScreen();
        Collection<IUserStub> friends = _serverStub.getFriends();
        if (friends == null) {
            _ui.showClientSideError("Server:" + _serverStub.getErrorMessage());
            return;
        }
        try {
            _ui.showRemoveFriend(userInput, friends);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        if (userInput.getSelectedAction().equals(EUserAction.ERemoveFriend)) {
            int friendID = (Integer) userInput.getParam(EUserParam.EUserID);
            if (_serverStub.removeFriend(friendID)) {
                _ui.showClientSideMessage(MSG_TO_THE_USER_REMOVED_FRIEND);
            } else {
                _ui.showClientSideError("Server:" + _serverStub.getErrorMessage());
            }
        }
        _nextScreen = EUserAction.EProfile;

    }

    private static void addFriend() {
        userInput = CClientFactory.getAddFriendScreen();

        try {
            _ui.showAddFriend(userInput);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


        if (userInput.getSelectedAction().equals(EUserAction.EAddFriend)) {
            String friendName = (String) userInput.getParam(EUserParam.EUsername);
            if (_serverStub.addFriend(friendName)) {
                _ui.showClientSideMessage(MSG_TO_THE_USER_ADDED_FRIEND);
                _nextScreen = EUserAction.EProfile;
            } else {
                _ui.showClientSideError("Server:" + _serverStub.getErrorMessage());
            }
        }
        _nextScreen = EUserAction.EProfile;
    }

    private static void showProfile() {

        userInput = CClientFactory.getProfileScreen();
        _ui.showProfile(userInput);
        _nextScreen = userInput.getSelectedAction();

        //if the back action has been selected -go  back to the the forums view
        if (userInput.getSelectedAction().equals(EUserAction.EBack)) {
            _nextScreen = EUserAction.EGetAllForums;
        }
    }
}
